import { CatmullRomCurve3, Color, ExtrudeGeometry3D, MathUtils3D, MeshLambertMaterial3D, Node3D, PerspectiveCamera3D, Scene3D, Shape, Vector2, Vector3, WebGLRenderer3D } from 'feng3d-three';

import { $set } from '@feng3d/serialization';
import { TrackballControls3D } from '../../extension/controls/TrackballControls3D';

let camera: PerspectiveCamera3D;
let scene: Scene3D;
let renderer: WebGLRenderer3D;
let controls: TrackballControls3D;

init();
animate();

function init()
{
    const info = document.createElement('div');
    info.style.position = 'absolute';
    info.style.top = '10px';
    info.style.width = '100%';
    info.style.textAlign = 'center';
    info.style.color = '#fff';
    info.style['link'] = '#f80';
    info.innerHTML = '<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - geometry extrude shapes';
    document.body.appendChild(info);

    renderer = new Node3D().addComponent('WebGLRenderer3D');
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    scene = renderer.addComponent('Scene3D');
    scene.background = new Color(0x222222);

    camera = new Node3D().addComponent('PerspectiveCamera3D', { fov: 45, aspect: window.innerWidth / window.innerHeight, near: 1, far: 1000 });
    camera.entity.position.set(0, 0, 500);

    controls = new TrackballControls3D(camera, renderer.domElement);
    controls.minDistance = 200;
    controls.maxDistance = 500;

    scene.addComponent('AmbientLight3D', { color: { value: 0x222222 } });

    const light = new Node3D().addComponent('PointLight3D', { color: { value: 0xffffff } });
    light.entity.position.copy(camera.entity.position);
    scene.entity.addChild(light.entity);

    //

    const closedSpline = new CatmullRomCurve3([
        new Vector3(-60, -100, 60),
        new Vector3(-60, 20, 60),
        new Vector3(-60, 120, 60),
        new Vector3(60, 20, -60),
        new Vector3(60, -100, -60)
    ]);

    closedSpline['curveType'] = 'catmullrom';
    closedSpline['closed'] = true;

    const extrudeSettings1 = {
        steps: 100,
        bevelEnabled: false,
        extrudePath: closedSpline
    };

    const pts1: Vector2[] = [];
    const count = 3;

    for (let i = 0; i < count; i++)
    {
        const l = 20;

        const a = 2 * i / count * Math.PI;

        pts1.push(new Vector2(Math.cos(a) * l, Math.sin(a) * l));
    }

    const shape1 = new Shape(pts1);

    const geometry1 = $set(new ExtrudeGeometry3D(), { shapes: shape1, options: extrudeSettings1 });

    const material1 = $set(new MeshLambertMaterial3D(), { color: { value: 0xb00000 }, wireframe: false });

    const mesh1 = new Node3D().addComponent('Mesh3D', { geometry: geometry1, material: material1 });

    scene.entity.addChild(mesh1.entity);

    //

    const randomPoints: Vector3[] = [];

    for (let i = 0; i < 10; i++)
    {
        randomPoints.push(new Vector3((i - 4.5) * 50, MathUtils3D.randFloat(-50, 50), MathUtils3D.randFloat(-50, 50)));
    }

    const randomSpline = new CatmullRomCurve3(randomPoints);

    //

    const extrudeSettings2 = {
        steps: 200,
        bevelEnabled: false,
        extrudePath: randomSpline
    };

    const pts2: Vector2[] = [];
    const numPts = 5;

    for (let i = 0; i < numPts * 2; i++)
    {
        const l = i % 2 === 1 ? 10 : 20;

        const a = i / numPts * Math.PI;

        pts2.push(new Vector2(Math.cos(a) * l, Math.sin(a) * l));
    }

    const shape2 = new Shape(pts2);

    const geometry2 = $set(new ExtrudeGeometry3D(), { shapes: shape2, options: extrudeSettings2 });

    const material2 = $set(new MeshLambertMaterial3D(), { color: { value: 0xff8000 }, wireframe: false });

    const mesh2 = new Node3D().addComponent('Mesh3D', { geometry: geometry2, material: material2 });

    scene.entity.addChild(mesh2.entity);

    //

    const materials = [material1, material2];

    const extrudeSettings3 = {
        depth: 20,
        steps: 1,
        bevelEnabled: true,
        bevelThickness: 2,
        bevelSize: 4,
        bevelSegments: 1
    };

    const geometry3 = $set(new ExtrudeGeometry3D(), { shapes: shape2, options: extrudeSettings3 });

    const mesh3 = new Node3D().addComponent('Mesh3D', { geometry: geometry3, materials });

    mesh3.entity.position.set(50, 100, 50);

    scene.entity.addChild(mesh3.entity);
}

function animate()
{
    requestAnimationFrame(animate);

    controls.update();
    renderer.render(scene, camera);
}
